/*!
    \file    ws2812.c
    \brief   WS2812灯带SPI+DMA驱动实现文件

    \version 2025-01-20, V1.0.0, WS2812驱动 for GD32C231C
*/

#include "ws2812.h"
#include "systick.h"
#include <string.h>
#include <stdlib.h>

/* 全局WS2812句柄 */
ws2812_handle_t g_ws2812;

/* 静态函数声明 */
static void ws2812_gpio_config(void);
static void ws2812_spi_config(void);
static void ws2812_dma_config(void);
static void ws2812_prepare_spi_data(void);
static uint8_t ws2812_byte_to_spi_bits(uint8_t byte, uint8_t *spi_bits);

/*!
    \brief      初始化WS2812驱动
    \param[in]  led_count: LED数量 (1-64)
    \param[out] none
    \retval     none
*/
void ws2812_init(uint16_t led_count)
{
    /* 参数检查 */
    if (led_count == 0 || led_count > WS2812_MAX_LEDS) {
        led_count = WS2812_MAX_LEDS;
    }
    
    /* 初始化WS2812句柄 */
    memset(&g_ws2812, 0, sizeof(ws2812_handle_t));
    g_ws2812.led_count = led_count;
    g_ws2812.state = WS2812_STATE_IDLE;
    g_ws2812.transmission_complete = true;
    g_ws2812.auto_refresh = false;
    g_ws2812.refresh_interval_ms = 25; /* 默认40Hz刷新率 */
    g_ws2812.last_update_time = 0;
    
    /* 计算缓冲区大小 */
    g_ws2812.buffer_size = WS2812_BUFFER_SIZE(led_count);
    
    /* 分配内存 */
    g_ws2812.spi_buffer = (uint8_t*)malloc(g_ws2812.buffer_size);
    g_ws2812.led_colors = (rgb_color_t*)malloc(led_count * sizeof(rgb_color_t));
    
    if (g_ws2812.spi_buffer == NULL || g_ws2812.led_colors == NULL) {
        /* 内存分配失败 */
        return;
    }
    
    /* 初始化缓冲区 */
    memset(g_ws2812.spi_buffer, 0, g_ws2812.buffer_size);
    memset(g_ws2812.led_colors, 0, led_count * sizeof(rgb_color_t));
    
    /* 配置GPIO */
    ws2812_gpio_config();
    
    /* 配置SPI */
    ws2812_spi_config();
    
    /* 配置DMA */
    ws2812_dma_config();
}

/*!
    \brief      反初始化WS2812驱动
    \param[in]  none
    \param[out] none
    \retval     none
*/
void ws2812_deinit(void)
{
    /* 禁用DMA */
    dma_channel_disable(WS2812_DMA_CHANNEL);
    dma_interrupt_disable(WS2812_DMA_CHANNEL, DMA_INT_FTF);
    
    /* 禁用SPI */
    spi_disable(WS2812_SPI);
    
    /* 释放内存 */
    if (g_ws2812.spi_buffer != NULL) {
        free(g_ws2812.spi_buffer);
        g_ws2812.spi_buffer = NULL;
    }
    
    if (g_ws2812.led_colors != NULL) {
        free(g_ws2812.led_colors);
        g_ws2812.led_colors = NULL;
    }
    
    /* 重置句柄 */
    memset(&g_ws2812, 0, sizeof(ws2812_handle_t));
}

/*!
    \brief      设置单个LED颜色
    \param[in]  led_index: LED索引 (0-63)
    \param[in]  color: RGB颜色值
    \param[out] none
    \retval     none
*/
void ws2812_set_led_color(uint16_t led_index, rgb_color_t color)
{
    if (led_index >= g_ws2812.led_count || g_ws2812.led_colors == NULL) {
        return;
    }
    
    g_ws2812.led_colors[led_index] = color;
}

/*!
    \brief      获取单个LED颜色
    \param[in]  led_index: LED索引 (0-63)
    \param[out] none
    \retval     RGB颜色值
*/
rgb_color_t ws2812_get_led_color(uint16_t led_index)
{
    rgb_color_t black = {0, 0, 0};
    
    if (led_index >= g_ws2812.led_count || g_ws2812.led_colors == NULL) {
        return black;
    }
    
    return g_ws2812.led_colors[led_index];
}

/*!
    \brief      设置多个LED颜色
    \param[in]  start_index: 起始LED索引
    \param[in]  colors: RGB颜色数组
    \param[in]  count: LED数量
    \param[out] none
    \retval     none
*/
void ws2812_set_led_colors(uint16_t start_index, rgb_color_t *colors, uint16_t count)
{
    uint16_t i;
    
    if (colors == NULL || g_ws2812.led_colors == NULL) {
        return;
    }
    
    for (i = 0; i < count && (start_index + i) < g_ws2812.led_count; i++) {
        g_ws2812.led_colors[start_index + i] = colors[i];
    }
}

/*!
    \brief      发送WS2812数据
    \param[in]  none
    \param[out] none
    \retval     none
*/
void ws2812_send_data(void)
{
    if (g_ws2812.state != WS2812_STATE_IDLE) {
        return; /* 正在发送中 */
    }
    
    /* 准备SPI数据 */
    ws2812_prepare_spi_data();
    
    /* 设置状态 */
    g_ws2812.state = WS2812_STATE_SENDING;
    g_ws2812.transmission_complete = false;
    
    /* 配置DMA传输 */
    dma_channel_disable(WS2812_DMA_CHANNEL);
    dma_memory_address_config(WS2812_DMA_CHANNEL, (uint32_t)g_ws2812.spi_buffer);
    dma_transfer_number_config(WS2812_DMA_CHANNEL, g_ws2812.buffer_size);
    
    /* 启动DMA传输 */
    dma_channel_enable(WS2812_DMA_CHANNEL);
    
    /* 启用SPI DMA发送 */
    spi_dma_enable(WS2812_SPI, SPI_DMA_TRANSMIT);
}

/*!
    \brief      检查WS2812传输是否完成
    \param[in]  none
    \param[out] none
    \retval     true: 传输完成, false: 传输中
*/
bool ws2812_is_transmission_complete(void)
{
    return g_ws2812.transmission_complete;
}

/*!
    \brief      启用WS2812自动刷新
    \param[in]  interval_ms: 刷新间隔(毫秒)
    \param[out] none
    \retval     none
*/
void ws2812_enable_auto_refresh(uint32_t interval_ms)
{
    g_ws2812.auto_refresh = true;
    g_ws2812.refresh_interval_ms = interval_ms;
    g_ws2812.last_update_time = 0; /* 立即触发第一次更新 */
}

/*!
    \brief      禁用WS2812自动刷新
    \param[in]  none
    \param[out] none
    \retval     none
*/
void ws2812_disable_auto_refresh(void)
{
    g_ws2812.auto_refresh = false;
}

/*!
    \brief      WS2812自动刷新处理函数 (在主循环中调用)
    \param[in]  none
    \param[out] none
    \retval     none
*/
void ws2812_auto_refresh_handler(void)
{
    if (!g_ws2812.auto_refresh) {
        return;
    }
    
    /* 直接发送数据，不依赖计数器 */
    if (ws2812_is_transmission_complete()) {
        ws2812_send_data();
    }
}

/*!
    \brief      WS2812 DMA中断处理函数
    \param[in]  none
    \param[out] none
    \retval     none
*/
void ws2812_dma_irq_handler(void)
{
    if (dma_interrupt_flag_get(WS2812_DMA_CHANNEL, DMA_INT_FLAG_FTF)) {
        /* 传输完成 */
        dma_interrupt_flag_clear(WS2812_DMA_CHANNEL, DMA_INT_FLAG_G);
        
        /* 禁用SPI DMA */
        spi_dma_disable(WS2812_SPI, SPI_DMA_TRANSMIT);
        
        /* 更新状态 */
        g_ws2812.state = WS2812_STATE_COMPLETE;
        g_ws2812.transmission_complete = true;
        
        /* 等待SPI发送完成 */
        while (RESET != spi_i2s_flag_get(WS2812_SPI, SPI_FLAG_TRANS));
        
        /* 重置状态为空闲 */
        g_ws2812.state = WS2812_STATE_IDLE;
    }
}

/*!
    \brief      设置所有LED为单一颜色
    \param[in]  color: RGB颜色值
    \param[out] none
    \retval     none
*/
void ws2812_set_all_color(rgb_color_t color)
{
    uint16_t i;
    
    for (i = 0; i < g_ws2812.led_count; i++) {
        ws2812_set_led_color(i, color);
    }
}

/*!
    \brief      彩虹效果
    \param[in]  offset: 颜色偏移量
    \param[out] none
    \retval     none
*/
void ws2812_rainbow_effect(uint8_t offset)
{
    uint16_t i;
    uint16_t hue;
    rgb_color_t color;
    
    for (i = 0; i < g_ws2812.led_count; i++) {
        hue = (i * 360 / g_ws2812.led_count + offset) % 360;
        color = ws2812_hsv_to_rgb(hue, 255, 255);
        ws2812_set_led_color(i, color);
    }
}

/*!
    \brief      呼吸灯效果
    \param[in]  color: 基础颜色
    \param[in]  brightness: 亮度 (0-255)
    \param[out] none
    \retval     none
*/
void ws2812_breathing_effect(rgb_color_t color, uint8_t brightness)
{
    rgb_color_t adjusted_color = ws2812_adjust_brightness(color, brightness);
    ws2812_set_all_color(adjusted_color);
}

/*!
    \brief      流水灯效果
    \param[in]  color: 流水灯颜色
    \param[in]  position: 当前位置
    \param[in]  tail_length: 拖尾长度
    \param[out] none
    \retval     none
*/
void ws2812_flowing_effect(rgb_color_t color, uint16_t position, uint8_t tail_length)
{
    uint16_t i;
    uint8_t brightness;
    rgb_color_t tail_color;
    
    /* 清除所有LED */
    ws2812_set_all_color(WS2812_COLOR_BLACK);
    
    /* 设置主LED */
    position = position % g_ws2812.led_count;
    ws2812_set_led_color(position, color);
    
    /* 设置拖尾 */
    for (i = 1; i <= tail_length; i++) {
        uint16_t tail_pos = (position + g_ws2812.led_count - i) % g_ws2812.led_count;
        brightness = 255 * (tail_length - i + 1) / (tail_length + 1);
        tail_color = ws2812_adjust_brightness(color, brightness);
        ws2812_set_led_color(tail_pos, tail_color);
    }
}

/*!
    \brief      HSV转RGB颜色 (复用DMX512实现)
    \param[in]  hue: 色调 (0-359)
    \param[in]  saturation: 饱和度 (0-255)
    \param[in]  value: 明度 (0-255)
    \param[out] none
    \retval     RGB颜色值
*/
rgb_color_t ws2812_hsv_to_rgb(uint16_t hue, uint8_t saturation, uint8_t value)
{
    rgb_color_t rgb;
    uint8_t region, remainder, p, q, t;
    
    if (saturation == 0) {
        rgb.red = value;
        rgb.green = value;
        rgb.blue = value;
        return rgb;
    }
    
    region = hue / 60;
    remainder = (hue - (region * 60)) * 255 / 60;
    
    p = (value * (255 - saturation)) >> 8;
    q = (value * (255 - ((saturation * remainder) >> 8))) >> 8;
    t = (value * (255 - ((saturation * (255 - remainder)) >> 8))) >> 8;
    
    switch (region) {
        case 0:
            rgb.red = value; rgb.green = t; rgb.blue = p;
            break;
        case 1:
            rgb.red = q; rgb.green = value; rgb.blue = p;
            break;
        case 2:
            rgb.red = p; rgb.green = value; rgb.blue = t;
            break;
        case 3:
            rgb.red = p; rgb.green = q; rgb.blue = value;
            break;
        case 4:
            rgb.red = t; rgb.green = p; rgb.blue = value;
            break;
        default:
            rgb.red = value; rgb.green = p; rgb.blue = q;
            break;
    }
    
    return rgb;
}

/*!
    \brief      调整RGB颜色亮度
    \param[in]  color: 原始颜色
    \param[in]  brightness: 亮度系数 (0-255)
    \param[out] none
    \retval     调整后的RGB颜色值
*/
rgb_color_t ws2812_adjust_brightness(rgb_color_t color, uint8_t brightness)
{
    rgb_color_t result;
    
    result.red = (color.red * brightness) / 255;
    result.green = (color.green * brightness) / 255;
    result.blue = (color.blue * brightness) / 255;
    
    return result;
}

/* 静态函数实现 */

/*!
    \brief      配置WS2812 GPIO
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void ws2812_gpio_config(void)
{
    /* 使能GPIO时钟 */
    rcu_periph_clock_enable(WS2812_GPIO_CLK);
    
    /* 配置SPI MOSI引脚 */
    gpio_mode_set(WS2812_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, WS2812_GPIO_PIN);
    gpio_output_options_set(WS2812_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_LEVEL_1, WS2812_GPIO_PIN);
    gpio_af_set(WS2812_GPIO_PORT, WS2812_GPIO_AF, WS2812_GPIO_PIN);
}

/*!
    \brief      配置WS2812 SPI
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void ws2812_spi_config(void)
{
    spi_parameter_struct spi_init_struct;
    
    /* 使能SPI时钟 */
    rcu_periph_clock_enable(WS2812_SPI_CLK);
    
    /* 配置SPI参数 */
    spi_struct_para_init(&spi_init_struct);
    spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode = SPI_MASTER;
    spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss = SPI_NSS_SOFT;
    spi_init_struct.prescale = SPI_PSC_8; /* 64MHz/8 = 8MHz, 接近6.4MHz */
    spi_init_struct.endian = SPI_ENDIAN_MSB;
    
    spi_init(WS2812_SPI, &spi_init_struct);
    
    /* 使能SPI */
    spi_enable(WS2812_SPI);
}

/*!
    \brief      配置WS2812 DMA
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void ws2812_dma_config(void)
{
    dma_parameter_struct dma_init_struct;
    
    /* 使能DMA时钟 */
    rcu_periph_clock_enable(WS2812_DMA_CLK);
    rcu_periph_clock_enable(RCU_DMAMUX);
    
    /* 配置DMA中断 */
    nvic_irq_enable(WS2812_DMA_IRQ, 2);
    
    /* 初始化DMA */
    dma_deinit(WS2812_DMA_CHANNEL);
    dma_struct_para_init(&dma_init_struct);
    
    dma_init_struct.request = WS2812_DMA_REQUEST;
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)g_ws2812.spi_buffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = g_ws2812.buffer_size;
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(WS2812_SPI);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    
    dma_init(WS2812_DMA_CHANNEL, &dma_init_struct);
    
    /* 配置DMA模式 */
    dma_circulation_disable(WS2812_DMA_CHANNEL);
    dma_memory_to_memory_disable(WS2812_DMA_CHANNEL);
    
    /* 禁用DMAMUX同步模式 */
    dmamux_synchronization_disable(DMAMUX_MUXCH2);
    
    /* 使能DMA传输完成中断 */
    dma_interrupt_enable(WS2812_DMA_CHANNEL, DMA_INT_FTF);
}

/*!
    \brief      准备SPI发送数据
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void ws2812_prepare_spi_data(void)
{
    uint16_t i, spi_index = 0;
    uint8_t spi_bits[8];
    
    if (g_ws2812.spi_buffer == NULL || g_ws2812.led_colors == NULL) {
        return;
    }
    
    /* 清空缓冲区 */
    memset(g_ws2812.spi_buffer, 0, g_ws2812.buffer_size);
    
    /* 转换LED颜色数据为SPI数据 */
    for (i = 0; i < g_ws2812.led_count; i++) {
        rgb_color_t *color = &g_ws2812.led_colors[i];
        
        /* WS2812使用GRB顺序 */
        /* 绿色 */
        ws2812_byte_to_spi_bits(color->green, spi_bits);
        memcpy(&g_ws2812.spi_buffer[spi_index], spi_bits, 8);
        spi_index += 8;
        
        /* 红色 */
        ws2812_byte_to_spi_bits(color->red, spi_bits);
        memcpy(&g_ws2812.spi_buffer[spi_index], spi_bits, 8);
        spi_index += 8;
        
        /* 蓝色 */
        ws2812_byte_to_spi_bits(color->blue, spi_bits);
        memcpy(&g_ws2812.spi_buffer[spi_index], spi_bits, 8);
        spi_index += 8;
    }
    
    /* 添加复位信号 (低电平) */
    memset(&g_ws2812.spi_buffer[spi_index], 0, WS2812_RESET_BITS);
}

/*!
    \brief      将字节转换为SPI位数据
    \param[in]  byte: 输入字节
    \param[out] spi_bits: 输出SPI位数组
    \retval     转换的位数
*/
static uint8_t ws2812_byte_to_spi_bits(uint8_t byte, uint8_t *spi_bits)
{
    uint8_t i;
    
    for (i = 0; i < 8; i++) {
        if (byte & (0x80 >> i)) {
            spi_bits[i] = WS2812_BIT_1; /* 逻辑1 */
        } else {
            spi_bits[i] = WS2812_BIT_0; /* 逻辑0 */
        }
    }
    
    return 8;
}